/*
 * Copyright (c) 2017,安徽皖通科技股份有限公司 All rights reserved.
 */

package com.wttech.dzzf.process.service.errordata;

import com.wtkj.vo.dzzf.base.kfwd.CardInfo;
import com.wtkj.vo.dzzf.base.kfwd.FundAccount;
import com.wttech.dzzf.process.dao.ErrorCertDataDao;
import com.wttech.dzzf.process.dao.TransferUserInfoDao;
import com.wttech.dzzf.process.model.errordata.HCBPhone;
import com.wttech.dzzf.process.service.base.BaseInfoService;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * 货车帮手机号导入服务
 *
 * @author MaShibo
 * @date 2017/10/26
 */
@Service
public class HcbPhonesImportService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HcbPhonesImportService.class);

    /**
     * 默认处理数量
     */
    private static final int DEFAULT_PROCESS_NUM = 10000;

    @Resource
    private ErrorCertDataDao errorCertDataDao;

    @Resource
    private TransferUserInfoDao transferUserInfoDao;

    @Resource
    private ThreadPoolTaskExecutor executor;

    @Resource
    private BaseInfoService baseInfoService;

    /**
     * Excel文件路径
     */
    private String excelFilePath;


    /**
     * 从Excel文件获取手机号信息-慢
     */
    public void process() {
        if (StringUtils.isBlank(excelFilePath)) {
            LOGGER.info("待处理文件路径未指定");
            return;
        }
        try (OPCPackage pkg = OPCPackage.open(new File(excelFilePath))) {
            XSSFWorkbook wb = new XSSFWorkbook(pkg);
            LOGGER.info("读取文件{}成功", excelFilePath);
            int sheetNum = wb.getNumberOfSheets();
            LOGGER.info("共{}个sheet", sheetNum);

            wb.forEach(sheet -> {
                LOGGER.info("开始解析Sheet[{}]", sheet.getSheetName());
                int rowStart = sheet.getFirstRowNum();
                int rowEnd = sheet.getLastRowNum();
                List<Future<Void>> futures = new ArrayList<>();
                for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
                    Row row = sheet.getRow(rowNum);
                    if (row == null) {
                        continue;
                    }
                    futures.add(executor.submit(new SubProcessThread(row)));
                }
                baseInfoService.getFutureResult(futures);
            });
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * 从数据库获取手机号信息
     */
    private void processV2() {
        Integer total = errorCertDataDao.queryHCBPhoneCount();
        LOGGER.info("共{}条货车帮手机号待处理", total);
        int count = (int) Math.ceil((double) total / DEFAULT_PROCESS_NUM);
        LOGGER.info("共需要处理{}次", count);
        List<Future<Void>> futures = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            futures.add(executor.submit(new SubPressThreadV2(i + 1)));
        }
        baseInfoService.getFutureResult(futures);
        executor.shutdown();
    }

    private class SubPressThreadV2 implements Callable<Void> {

        private int count;

        SubPressThreadV2(int count) {
            this.count = count;
        }

        @Override
        public Void call() throws Exception {
            LOGGER.info("第{}次开始执行", count);
            int startRow = (count - 1) * DEFAULT_PROCESS_NUM + 1;
            int endRow = count * DEFAULT_PROCESS_NUM;
            try {
                List<HCBPhone> hcbPhones = errorCertDataDao.queryHCBPhoneInfos(startRow, endRow);
                hcbPhones.forEach(this::correctPhoneNo);
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
            LOGGER.info("第{}次结束执行", count);
            return null;
        }

        /**
         * 纠正/填充错误的手机号
         *
         * @param hcbPhone 货车帮手机号信息
         */
        private void correctPhoneNo(HCBPhone hcbPhone) {
            String ecardNo = hcbPhone.getEcardNo();
            String phoneNo = hcbPhone.getPhoneNo();
//            correctCardPhone(ecardNo, phoneNo);
            correctAccountPhone(ecardNo, phoneNo);
        }

        private void correctCardPhone(String ecardNo, String phoneNo) {
            LOGGER.info("正在处理卡号【{}】", ecardNo);
            try {
                //创建卡片信息
                CardInfo cardQuery = new CardInfo();
                cardQuery.setECardNo(ecardNo);
                @SuppressWarnings("unchecked")
                List<CardInfo> cardInfos = (List<CardInfo>) transferUserInfoDao.queryDzzfList(cardQuery);
                if (!CollectionUtils.isEmpty(cardInfos)) {
                    CardInfo cardInfo = cardInfos.get(0);
                    transferUserInfoDao.createTestObjcet(cardInfo);

                    //更新卡片信息
                    cardInfo.setPhoneNo(phoneNo);
                    transferUserInfoDao.updateDzzfObject(cardInfo);
                }
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
        }

        private void correctAccountPhone(String ecardNo, String phoneNo) {
            try {
                Optional<String> fop = errorCertDataDao.queryFundAccountIdByCardNo(ecardNo);
                if (!fop.isPresent()) {
                    LOGGER.warn("货车帮卡号{}不存在对应的资金账户", ecardNo);
                    return;
                }
                String fundAccountId = fop.get();
                LOGGER.info("正在处理资金账户【{}】", fundAccountId);
                FundAccount query = new FundAccount();
                query.setFundAccountId(fundAccountId);
                FundAccount exist = (FundAccount) transferUserInfoDao.queryTestObject(query);
                FundAccount updateObj;
                if (exist != null) {
                    LOGGER.info("资金账户【{}】已创建", fundAccountId);
                    List<CardInfo> cardInfos = transferUserInfoDao.queryCardInfosByFundAccount(fundAccountId);
                    if (!CollectionUtils.isEmpty(cardInfos)){
                        CardInfo cardInfo = cardInfos.get(0);

                        if (StringUtils.isNotBlank(cardInfo.getPhoneNo()) && cardInfo.getPhoneNo().length() == 11){
                            updateObj = new FundAccount();
                            updateObj.setFundAccountId(fundAccountId);
                            updateObj.setPhone(cardInfo.getPhoneNo());
                            transferUserInfoDao.updateDzzfObject(updateObj);
                        }
                    }
                    return;
                }
                query = (FundAccount) transferUserInfoDao.queryDzzfObject(query);
                if (query != null) {
//                    transferUserInfoDao.createTestObjcet(query);

                    //更新资金账户信息
                    updateObj = new FundAccount();
                    updateObj.setFundAccountId(fundAccountId);
                    updateObj.setPhone(phoneNo);
                    transferUserInfoDao.updateDzzfObject(updateObj);
                }
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
        }

    }

    private class SubProcessThread implements Callable<Void> {

        private Row row;


        SubProcessThread(Row row) {
            this.row = row;
        }

        @Override
        public Void call() throws Exception {
            LOGGER.info("开始处理第{}行数据", row.getRowNum() + 1);
            //第2行卡号
            String ecardNo = row.getCell(1).getStringCellValue();
            //第3行手机号
            String phoneNo = row.getCell(2).getStringCellValue();
            Optional<String> fop = errorCertDataDao.queryFundAccountIdByCardNo(ecardNo);
            fop.ifPresent(fundAccountId -> {
                try {
                    errorCertDataDao.updatePhoneByFundAccountId(phoneNo, fundAccountId);
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }
            });
            return null;
        }
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HcbPhonesImportService service = context.getBean(HcbPhonesImportService.class);
        service.processV2();
    }
}
